#include "Buffer.h"

#include <errno.h>
#include <sys/uio.h>
/*
从fd读取数据，Poller默认是LT模式
LT（level triage）模式：只要就绪就会一直触发
ET（edge triage）模式：读事件（从无到有）才会触发。写事件（从有到无）才会触发。并且满足条件只会触发一次，下一次触发得重新满足
    Buffer缓冲区是有大小的，但是从fd读取数据时候，是不知道tcp数据的大小
*/

/*
 ::readv readv() 函数允许你从一个文件描述符 fd 读取数据，并将这些数据分散存储到多个不连续的内存缓冲区中。
    这种操作也被称为 “分散读”，它可以避免多次调用 read() 函数来将数据读入多个缓冲区，提高了数据读取的效率。
*/
size_t Buffer::readFd(int fd, int* saveErrno)
{
    char extrabuf[65536] = { 0 }; //栈上内存
    struct iovec vec[2];
    const size_t writeable = writableBytes();   //Buffer底层剩余的缓冲区数据
    vec[0].iov_base = begin() + writeIndex_;    //写缓冲区的起始地址
    vec[0].iov_len = writeable;

    vec[1].iov_base = extrabuf;
    vec[1].iov_len = sizeof(extrabuf);

    //当writeable < 64K。 缓冲区为2块；如果writeable >= 64k，那么缓冲区为1块
    const int iovcnt = writeable < sizeof(extrabuf) ? 2 : 1;
    const ssize_t n = ::readv(fd, vec, iovcnt);     //从fd读取数据带缓冲区
    if(n < 0)
    {
        *saveErrno = errno;
    }
    else if(n <= writeable)
    {
        //buffer的可写缓冲区可以满足本次的数据大小
        writeIndex_ += n;
    }
    else
    {
        //writable < n : 也就是说extrabuf也被写入数据了
        //writeIndex_ += writeable;
        writeIndex_ = buffer_.size();
        append(extrabuf, n - writeable);
    }
    return n;
}

